package com.fary.chapter01_aqs.ext_reentrantLock;

public class TestFaryReentrantLock {

    /**
     * 非公平锁：
     * 1.reentrantLock.lock(),尝试快速获取锁（获取成功state=1，ownerThread）
     * 2.获取锁失败，再尝试获取锁
     * 3.state=0，尝试获取锁；state>=1，重入锁（获取成功state+1，ownerThread）
     * 4.获取锁失败，将当前线程节点添加到锁池队列中，先尝试快速追加在尾部
     * 5.追加尾部失败，自旋追加在尾部（创建头结点，追加在尾结点之后）
     * 6.自旋获取锁（前一个节点是头结点，尝试获取锁，直接返回）
     * 7.获取锁失败，判断是否可以挂起当前线程（上一个节点的waitStatus=-1，表示可以挂起阻塞）
     * 8.如果上一个节点的waitStatus=2，表示上一个节点被取消了，那么往前找waitStatus<=0的节点，继续自旋获取锁6
     * 9.如果上一个节点的waitStatus=0或者PROPAGATE，修改waitStatus的值为-1，继续自旋获取锁6
     * 
     * 公平锁：
     * 1.reentrantLock.lock()
     * 2.开始尝试获取锁
     * 3.state=0，尝试获取锁（会判断当前队列有没有在排队的，没有则会尝试获取锁）；state>=1，重入锁（获取成功state+1，ownerThread）
     * 4.获取锁失败，将当前线程节点添加到锁池队列中，先尝试快速追加在尾部
     * 5.追加尾部失败，自旋追加在尾部（创建头结点，追加在尾结点之后）
     * 6.自旋获取锁（前一个节点是头结点，尝试获取锁，直接返回）
     * 7.获取锁失败，判断是否可以挂起当前线程（上一个节点的waitStatus=-1，表示可以挂起阻塞）
     * 8.如果上一个节点的waitStatus=2，表示上一个节点被取消了，那么往前找waitStatus<=0的节点，继续自旋获取锁6
     * 9.如果上一个节点的waitStatus=0或者PROPAGATE，修改waitStatus的值为-1，继续自旋获取锁6
     *
     *
     * 非公平锁和公平锁释放锁
     * 1.reentrantLock.unlock();
     * 2.尝试释放锁（getState() - releases），State=0全部释放锁，返回true；state>=1，重入锁，返回false
     * 3.全部释放锁之后，头结点不为空，并且waitStatus的值不为0，唤醒下一个节点
     * 4.如果头结点waitStatus的值<0，修改waitStatus的值为0
     * 5.如果头结点waitStatus的值>=0，从尾节点开始向前找起, 直到找到距离head节点最近的ws<=0的节点，唤醒此节点
     */
    public static void main(String[] args) {
        FaryReentrantLock reentrantLock = new FaryReentrantLock(true);
//        reentrantLock.lock();

        new Thread(new Runnable() {
            @Override
            public void run() {
                reentrantLock.lock();
                System.out.println(Thread.currentThread().getName());
                reentrantLock.unlock();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                reentrantLock.lock();
                System.out.println(Thread.currentThread().getName());
                reentrantLock.unlock();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                reentrantLock.lock();
                System.out.println(Thread.currentThread().getName());
                reentrantLock.unlock();
            }
        }).start();

        System.out.println(Thread.currentThread().getName());
//        reentrantLock.unlock();
    }

}
